package gotask

import (
	log "github.com/sirupsen/logrus"
	"sync"
)

/*
concurrencyLimiter并发控制器，
limit：控制并发数量
blockingNum: 阻塞在队列中的数量
cond： 同步条件
*/
type concurrencyLimiter struct {
	runningNum int
	limit int
	blockingNum int
	cond *sync.Cond
}

//创建新的并发控制器
func NewConcurrencyLimiter(limit int) *concurrencyLimiter {
	l := new(sync.Mutex)
	return &concurrencyLimiter{
		limit:limit,
		cond: sync.NewCond(l),
	}
}

// 重置 limit值
func (c *concurrencyLimiter) Reset(limit int) {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	tmp := c.limit
	c.limit = limit
	blockingNum := c.blockingNum

	if limit-tmp > 0 && blockingNum > 0 {
		for i := 0; i < limit - tmp && blockingNum > 0; i++ {
			c.cond.Signal()
			blockingNum--
		}
	}
}

// Get 当没有资源时，会阻塞
func (c *concurrencyLimiter) Get() {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	if c.runningNum < c.limit {
		log.Infof("runningnum[%d] is less than limit[%d], get a resource", c.runningNum, c.limit)
		c.runningNum++
		return
	}

	c.blockingNum++
	for !(c.runningNum < c.limit) {
		log.Infof("runningunm[%d] is not less than limitd[%d],waitting for...", c.runningNum, c.limit)
		c.cond.Wait()
	}

	c.runningNum++
	c.blockingNum--
}

//Release 释放一个资源
func (c *concurrencyLimiter) Release() {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	if c.blockingNum > 0 {
		c.runningNum--
		c.cond.Signal()
		return
	}

	c.runningNum--
}